/*
 * @Date: 2022-11-30 16:05:41
 * @LastEditors: fuzhuang
 * @LastEditTime: 2023-12-11 09:32:42
 * @FilePath: \golib\ck\ck_db.go
 * @Description:
 */
package ck

import (
	"errors"
	"time"

	"gitee.com/haodreams/godriver/clickhouse"
	"gitee.com/haodreams/golib/gensql"
	"gitee.com/haodreams/golib/logs"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
)

//单库使用

type DB struct {
	*gorm.DB
	enable bool
}

/**
 * @description:是否启用
 * @return {*}
 */
func (m *DB) Enabled() bool {
	return m.enable
}

func (m *DB) Setup(dsn string, enable bool) (err error) {
	if !enable || dsn == "" {
		err = errors.New("禁用clickhouse功能")
		return
	}
	db, err := gorm.Open(clickhouse.Open(dsn), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true,
		},
	})
	if err != nil {
		return
	}

	d, err := db.DB()
	if err != nil {
		return
	}

	d.SetMaxIdleConns(1)
	d.SetMaxOpenConns(5)
	d.SetConnMaxLifetime(time.Second * 3600)
	d.SetConnMaxIdleTime(time.Second * 900)
	m.DB = db
	m.enable = enable
	return
}

func (m *DB) Exec(sql string, values ...interface{}) (tx *DB) {
	if !m.enable {
		return
	}
	m.DB.Exec(sql, values...)
	return m
}

/*
*公用方法-写入clickhouse数据库
*param(clickhouse连接,json数组)
*return(变化行数，错误信息)
 */
func (m *DB) InsertObjects(rows interface{}) (count int, err error) {
	if !m.enable {
		return
	}

	if m.DB == nil {
		err = errors.New("没有有效的数据库对象")
		return
	}
	sql, records, err := gensql.GenSQLData(m.DB, rows)
	if err != nil {
		return
	}

	if len(records) == 0 {
		return
	}

	count, err = m.Insert(sql, records)
	if err != nil {
		logs.Warn("写入失败, 再试一次")
		return m.Insert(sql, records)
	}
	return
}

/**
 * @description: 写入数据到clickhouse
 * @param {int} dbIdx 使用第几个DB
 * @param {interface{}} rows
 * @return {*}
 */
func (m *DB) Insert(sql string, rows [][]interface{}) (count int, err error) {
	if !m.enable {
		return
	}
	db, err := m.DB.DB()
	if err != nil {
		return
	}
	tx, err := db.Begin()
	if err != nil {
		logs.Error(sql, err)
		return
	}
	stmt, err := tx.Prepare(sql)
	if err != nil {
		tx.Rollback()
		logs.Error(err, sql)
		return
	}

	defer stmt.Close()

	for i := range rows {
		_, err = stmt.Exec(rows[i]...)
		if err != nil {
			logs.Warn(sql, "exec insert ", err)
			continue
		}
		count++
	}

	//logs.Infof("%s connect  parser to sql:%d used time:%s", msg, len(vals), time.Since(now))

	if err := tx.Commit(); err != nil {
		logs.Error(err)
	}
	return
}
